package com.white.commonlib.utils;

import android.content.Context;
import android.os.Environment;
import android.os.StatFs;
import android.text.TextUtils;

import com.white.ndkmaster.NativeX;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by ytf on 2016/11/10.
 */

public class FileUtils
{

    /***
     * 写字符串到文件
     * @param absPath   绝对路径
     * @param content   写入的内容
     */
    public static void writeString(String absPath, String content)
    {
        if(!TextUtils.isEmpty(absPath) && !TextUtils.isEmpty(content))
        {
            File f = new File(absPath);
            String parent = f.getParent();
            f = new File(parent);
            if(!f.exists())
            {
                f.mkdirs();
                NativeX.writeString(absPath, content);
            }
        }
    }

    /**
     * 根据文件绝对路径获取文件名
     *
     * @param filePath
     * @return
     */
    public static String getFileName(String filePath)
    {
        if (TextUtils.isEmpty(filePath))
            return "";
        return filePath.substring(filePath.lastIndexOf(File.separator) + 1);
    }

    /**
     * 根据文件的绝对路径获取文件名但不包含扩展名
     *
     * @param filePath
     * @return
     */
    public static String getFileNameNoSuffix(String filePath)
    {
        if (TextUtils.isEmpty(filePath))
        {
            return "";
        }
        String fileName = getFileName(filePath);
        return fileName.substring(0, fileName.lastIndexOf("."));
    }

    /**
     * 获取文件后缀名
     *
     * @param fileName
     * @return
     */
    public static String getFileSuffix(String fileName)
    {
        if (TextUtils.isEmpty(fileName))
            return "";

        int point = fileName.lastIndexOf('.');
        return fileName.substring(point + 1);
    }

    /**
     * 获取文件大小
     *
     * @param filePath
     * @return
     */
    public static long getFileSize(String filePath)
    {
        long size = 0;

        File file = new File(filePath);
        if (file != null && file.exists())
        {
            size = file.length();
        }
        return size;
    }

    /**
     * 获取目录文件大小
     *
     * @param dir
     * @return
     */
    public static long getDirSize(File dir)
    {
        if (dir == null)
        {
            return 0;
        }
        if (!dir.isDirectory())
        {
            return 0;
        }
        long dirSize = 0;
        File[] files = dir.listFiles();
        if(files != null && files.length > 0)
        {
            for (File file : files)
            {
                if (file.isFile())
                {
                    dirSize += file.length();
                } else if (file.isDirectory())
                {
                    dirSize += getDirSize(file); // 递归调用继续统计
                }
            }
        }
        return dirSize;
    }

    /***
     * 删除目录及目录下所有文件
     * @param dir
     * @return
     */
    private static boolean deleteDir(File dir)
    {
        if (dir != null && dir.isDirectory())
        {
            String[] children = dir.list();
            for (int i = 0; i < children.length; i++)
            {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success)
                {
                    return false;
                }
            }
        }
        return dir.delete();
    }

    /**
     * 获取目录下文件的个数
     *
     * @param dir
     * @return
     */
    public long getDirFileCount(File dir)
    {
        long count = 0;
        if (dir != null && dir.exists())
        {
            File[] files = dir.listFiles();
            if (files != null && files.length > 0)
            {
                count = files.length;
                for (File file : files)
                {
                    if (file.isDirectory())
                    {
                        count += getDirFileCount(file);// 递归
                        count--;
                    }
                }
            }
        }
        return count;
    }

    public static byte[] streamToBytes(InputStream in) throws IOException
    {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int ch;
        while ((ch = in.read()) != -1)
        {
            out.write(ch);
        }
        byte buffer[] = out.toByteArray();
        out.close();
        return buffer;
    }

    /***
     * 文件转字节数组
     *
     * @param f
     * @return
     */
    private static byte[] fileToByteArray(File f)
    {
        if (f == null || (!f.exists()))
        {
            return null;
        }
        FileInputStream fis = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try
        {
            fis = new FileInputStream(f);
            byte[] buffer = new byte[1024];
            int readCount;
            while ((readCount = fis.read(buffer)) > 0)
            {
                baos.write(buffer, 0, readCount);
            }
            baos.flush();
            return baos.toByteArray();
        } catch (FileNotFoundException e)
        {
            e.printStackTrace();
            return null;
        } catch (IOException e)
        {
            e.printStackTrace();
            return null;
        } finally
        {
            try
            {
                fis.close();
                baos.close();
            } catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

    /***
     * 字节数组转文件
     *
     * @param datas
     * @param outFilePath 文件的绝对路径
     * @return
     */
    private static File byteArrayToFile(byte[] datas, String outFilePath)
    {

        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        File f = new File(outFilePath);
        try
        {
            fos = new FileOutputStream(f);
            bos = new BufferedOutputStream(fos);
            bos.write(datas);
            bos.flush();
            return f;
        } catch (FileNotFoundException e)
        {
            e.printStackTrace();
            return null;
        } catch (IOException e)
        {
            e.printStackTrace();
            return null;
        } finally
        {
            try
            {
                if (fos != null)
                {
                    fos.close();
                }
                if (bos != null)
                {
                    bos.close();
                }
            } catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

    /**
     * 计算SD卡的剩余空间
     *
     * @return 返回-1，说明没有安装sd卡
     */
    public static long getFreeDiskSpace()
    {
        String status = Environment.getExternalStorageState();
        long freeSpace = 0;
        if (status.equals(Environment.MEDIA_MOUNTED))
        {
            try
            {
                File path = Environment.getExternalStorageDirectory();
                StatFs stat = new StatFs(path.getPath());
                long blockSize = stat.getBlockSize();
                long availableBlocks = stat.getAvailableBlocks();
                freeSpace = availableBlocks * blockSize / 1024;
            } catch (Exception e)
            {
                e.printStackTrace();
            }
        } else
        {
            return -1;
        }
        return (freeSpace);
    }

    /**
     * 创建目录，如果该目录存在则直接返回该路径
     *
     * @param parentPath 父目录，传绝对路径
     * @param directoryName 可以是单个目录， 也可以带子目录 如: /dir 或者 /dir/childDir
     * @return
     */
    public static String mkDir(String parentPath, String directoryName)
    {
        if (!TextUtils.isEmpty(directoryName))
        {
            if (!directoryName.startsWith("/"))
            {
                directoryName = "/" + directoryName;
            }

            File newPath = new File(parentPath, directoryName);
            if (!newPath.exists())
            {
                if (newPath.mkdirs())
                {
                    return newPath.getAbsolutePath();
                }else
                {
                    return null;
                }
            } else
            {
                return newPath.getAbsolutePath();
            }
        }
        return null;
    }


    /**
     * 删除目录(包括：目录里的所有文件)
     *
     * @param fileAbsolutePath
     * @return
     */
    public static boolean deleteDirectory(String fileAbsolutePath)
    {
        boolean status;
        SecurityManager checker = new SecurityManager();
        if (!TextUtils.isEmpty(fileAbsolutePath))
        {
            File newPath = new File(fileAbsolutePath);
            checker.checkDelete(newPath.toString());
            if (newPath.isDirectory())
            {
                String[] listfile = newPath.list();
                try
                {

                    for (int i = 0; i < listfile.length; i++)
                    {
                        File deletedFile = new File(newPath.toString() + "/" + listfile[i].toString());
                        deletedFile.delete();
                    }
                    newPath.delete();
                    status = true;
                } catch (Exception e)
                {
                    e.printStackTrace();
                    status = false;
                }

            } else
                status = false;
        } else
            status = false;
        return status;
    }


    /**
     * 重命名
     *
     * @param oldName
     * @param newName
     * @return
     */
    public static boolean rename(String oldName, String newName)
    {
        File f = new File(oldName);
        return f.renameTo(new File(newName));
    }

    /**
     * 列出root目录下所有子目录，不包括文件
     *
     * @param root
     * @return 绝对路径
     */
    public static List<String> listChildDir(String root)
    {
        List<String> allDir = new ArrayList<String>();
        SecurityManager checker = new SecurityManager();
        File path = new File(root);
        checker.checkRead(root);
        // 过滤掉以.开始的文件夹
        if (path.isDirectory())
        {
            for (File f : path.listFiles())
            {
                if (f.isDirectory() && !f.getName().startsWith("."))
                {
                    allDir.add(f.getAbsolutePath());
                }
            }
        }
        return allDir;
    }

    /**
     * 获取一个文件夹下的所有文件，不包括目录
     *
     * @param root
     * @return
     */
    public static List<File> listDirSingleFiles(String root)
    {
        List<File> allDir = new ArrayList<File>();
        SecurityManager checker = new SecurityManager();
        File path = new File(root);
        checker.checkRead(root);
        File[] files = path.listFiles();
        for (File f : files)
        {
            if (f.isFile())
                allDir.add(f);
        }
        return allDir;
    }

    /***
     * 在app的主目录下面创建子目录，app的主目录是放到sd卡外面的，该方式创建的目录在app卸载后不会自动清除
     * @param newPath
     * @return
     */
    public static String createPathBasedOnApp(Context ctx, String newPath)
    {
        String appPath = getAppPathCustom(ctx);
        if(!newPath.startsWith("/"))
        {
            newPath = File.separator+newPath;
        }
        File f = new File(appPath, newPath);
        if (!f.exists())
        {
            if (f.mkdirs())
            {
                return f.getAbsolutePath();
            } else
            {
                return null;
            }
        } else
        {
            return f.getAbsolutePath();
        }
    }

    /**
     * 获取缓存路径
     *
     * @param context   设备上下文
     * @param externOrInner true表示获取外部缓存目录，如果外部不可用就会返回内部缓存目录，false表示内部缓存目录
     * @return
     */
    public static String getCacheDir(Context context, boolean externOrInner)
    {
        String cachePath = null;
        //获取外部缓存目录
        if(externOrInner)
        {
            //准备就绪就返回，否则返回空
            if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
            {
                File f = context.getExternalCacheDir();
                if(f != null)
                {
                    cachePath = f.getAbsolutePath();
                }
            }else
            {
                return context.getCacheDir().getAbsolutePath();
            }
            return cachePath;
        }else
        {
            //返回内部缓存目录
            return context.getCacheDir().getAbsolutePath();
        }
    }

    /**
     * 获取文件路径
     *
     * @param context   设备上下文
     * @param externOrInner true表示获取外部files目录，如果外部不可用就会返回内部files目录，false表示内部files目录
     * @return
     */
    public static String getFilesDir(Context context, boolean externOrInner)
    {
        String cachePath = null;
        //获取外部缓存目录
        if(externOrInner)
        {
            //准备就绪就返回，否则返回空
            if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
            {
                File f = context.getExternalFilesDir(null);
                if(f != null)
                {
                    cachePath = f.getAbsolutePath();
                }
            }else
            {
                return context.getFilesDir().getAbsolutePath();
            }
            return cachePath;
        }else
        {
            //返回内部缓存目录
            return context.getFilesDir().getAbsolutePath();
        }
    }

    /***
     * 获得外部特定的一个文件夹
     * @param ctx
     * @param path 不带 '/'
     * @return
     */
    public static String getExternalSpecialFilesDir(Context ctx, String path)
    {
        String externalCache = getFilesDir(ctx, true);
        File f = new File(externalCache, path);
        if(!f.exists())
        {
            if(f.mkdirs())
                return f.getAbsolutePath();
            return null;
        }else
        {
            return f.getAbsolutePath();
        }
    }

    /***
     * 获得外部的特定的缓存文件夹
     * @param ctx
     * @param path
     * @return
     */
    public static String getExternalSpecialCacheDir(Context ctx, String path)
    {
        String externalCache = getCacheDir(ctx, true);
        File f = new File(externalCache, path);
        if(!f.exists())
        {
            if(f.mkdirs())
                return f.getAbsolutePath();
            return null;
        }else
        {
            return f.getAbsolutePath();
        }
    }

    /**
     * 获取应用程序内部缓存文件夹下的指定目录
     *
     * @param context
     * @param dir
     * @return
     */
    public static String createDirOnAppCache(Context context, String dir)
    {
        String savePath = context.getCacheDir().getAbsolutePath() + "/" + dir;
        File savedir = new File(savePath);
        if (!savedir.exists())
        {
            savedir.mkdirs();
        }
        return savePath;
    }

    /***
     * 根据包名最后一个单词，在sd卡或者内部存储创建一个目录
     * @param ctx
     * @return
     */
    public static String getAppPathCustom(Context ctx)
    {
        String appName = ctx.getPackageName();
        appName = appName.substring(appName.lastIndexOf(".") + 1, appName.length());
        return createDirectoryAuto(ctx, appName);
    }

    /**
     * 创建目录, 会根据外部存储是否可用自行创建到外部或内部存储
     *
     * @param directoryName 可以是单个目录， 也可以带子目录 如: /dir 或者 /dir/childDir
     * @return
     */
    public static String createDirectoryAuto(Context ctx, String directoryName)
    {
        if (!TextUtils.isEmpty(directoryName))
        {
            if (!directoryName.startsWith("/"))
            {
                directoryName = "/" + directoryName;
            }

            File path = null;
            //初次调用方法时进行判断
            if(((Integer) PreferenceUtils.get("storageState", -1)) == -1)
            {
                //避免找不到文件，在确定外部存储不可用或可用的时候，保存该状态
                if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
                {
                    path = Environment.getExternalStorageDirectory();
                    //SD可用
                    PreferenceUtils.put("storageState", 1);
                } else
                {
                    path = ctx.getFilesDir();
                    //外部存储不可用，只能使用内部存储
                    PreferenceUtils.put("storageState", 0);
                }
            }else if(((Integer) PreferenceUtils.get("storageState", -1)) == 1)
            {
                //外部存储可用,不可用时抛异常
                if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
                {
                    path = Environment.getExternalStorageDirectory();
                }else
                {
                    throw new RuntimeException("sd卡未准备就绪");
                }
            }else
            {
                //外部存储不可用
                path = ctx.getFilesDir();
            }

            File newPath = new File(path, directoryName);
            if (!newPath.exists())
            {
                if (newPath.mkdirs())
                {
                    return newPath.getAbsolutePath();
                }
            } else
            {
                return newPath.getAbsolutePath();
            }
        }
        return null;
    }

}
